<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>JSON数据表格管理</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <style>
        body { 
            font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; 
            padding: 20px; 
            background-color: #f8f9fa; 
        }
        
        /* 通用样式 */
        .header { 
            display: flex; 
            justify-content: space-between; 
            align-items: center; 
            margin-bottom: 20px; 
        }
        .table-container { 
            background: white; 
            border-radius: 10px; 
            box-shadow: 0 2px 10px rgba(0,0,0,0.05); 
            overflow: hidden; 
            margin: 0 auto;
        }
        .table-responsive { 
            overflow-x: auto; 
        }
        .table { 
            margin-bottom: 0; 
        }
        .table th { 
            background-color: #f8f9fa; 
            position: sticky; 
            top: 0; 
            white-space: nowrap;
        }
        .search-box { 
            margin-bottom: 15px; 
            position: relative; 
            max-width: 400px;
        }
        .search-box i { 
            position: absolute; 
            left: 12px; 
            top: 12px; 
            color: #6c757d; 
        }
        .search-box input { 
            padding-left: 35px; 
            border-radius: 20px; 
        }
        .action-btn { 
            margin: 0 3px; 
            padding: 5px 10px; 
            font-size: 12px; 
        }
        .sort-icon { 
            cursor: pointer; 
            margin-left: 5px; 
        }
        .loading { 
            text-align: center; 
            padding: 20px; 
        }
        .empty-table { 
            text-align: center; 
            padding: 30px; 
            color: #6c757d; 
        }
        .modal-content { 
            border-radius: 10px; 
        }
        .toast-container { 
            position: fixed; 
            top: 20px; 
            right: 20px; 
            z-index: 1100; 
        }
        .pagination-container { 
            display: flex; 
            justify-content: space-between; 
            align-items: center; 
            margin-top: 15px; 
            padding: 15px;
        }
        .page-size-select { 
            width: 100px; 
        }
        .is-invalid { 
            border-color: #dc3545; 
        }
        .invalid-feedback { 
            color: #dc3545; 
            font-size: 0.875em; 
        }
        .export-btn { 
            margin-left: 10px; 
        }
        
        /* 电脑端特定样式 */
        @media (min-width: 768px) {
            body {
                padding: 30px;
            }
            .table-container {
                max-width: 1200px;
            }
            .header h4 {
                font-size: 1.5rem;
            }
            .table th, .table td {
                padding: 12px 15px;
                font-size: 0.95rem;
            }
            .action-btn {
                padding: 6px 12px;
                font-size: 0.9rem;
            }
            .search-box {
                max-width: 500px;
            }
            .modal-dialog {
                max-width: 600px;
            }
            .table-hover tbody tr:hover {
                background-color: rgba(0, 0, 0, 0.02);
            }
            .btn {
                padding: 0.5rem 1rem;
            }
        }
        
        /* 移动端特定样式 */
        @media (max-width: 767px) {
            body {
                padding: 15px;
            }
            .table-container {
                width: 100%;
            }
            .header h4 {
                font-size: 1.2rem;
            }
            .table th, .table td {
                padding: 8px 10px;
                font-size: 0.85rem;
            }
            .pagination-container {
                flex-direction: column;
                gap: 10px;
            }
            .page-size-select {
                width: 100%;
            }
        }
    </style>
</head>
<body>
    <div class="container-fluid">
        <div class="header">
            <h4>数据表格管理</h4>
            <div>
                <button class="btn btn-primary btn-sm" id="addBtn">
                    <i class="fas fa-plus"></i> 添加记录
                </button>
                <button class="btn btn-success btn-sm export-btn" id="exportBtn">
                    <i class="fas fa-download"></i> 导出
                </button>
            </div>
        </div>

        <div class="search-box">
            <i class="fas fa-search"></i>
            <input type="text" class="form-control" id="searchInput" placeholder="搜索...">
        </div>

        <div class="table-container">
            <div class="table-responsive">
                <table class="table table-hover" id="dataTable">
                    <thead>
                        <tr id="tableHeader"></tr>
                    </thead>
                    <tbody id="tableBody">
                        <tr>
                            <td colspan="100" class="loading">
                                <div class="spinner-border text-primary" role="status">
                                    <span class="visually-hidden">加载中...</span>
                                </div>
                                <p>正在加载数据...</p>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            
            <div class="pagination-container p-3">
                <div>
                    <select class="form-select form-select-sm page-size-select" id="pageSizeSelect">
                        <option value="5">5条/页</option>
                        <option value="10" selected>10条/页</option>
                        <option value="20">20条/页</option>
                        <option value="50">50条/页</option>
                    </select>
                </div>
                <nav>
                    <ul class="pagination pagination-sm" id="pagination">
                        <!-- 分页按钮将通过JS动态生成 -->
                    </ul>
                </nav>
            </div>
        </div>
    </div>

    <!-- 添加/编辑模态框 -->
    <div class="modal fade" id="editModal" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="modalTitle">添加记录</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body" id="modalForm"></div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                    <button type="button" class="btn btn-primary" id="saveBtn">保存</button>
                </div>
            </div>
        </div>
    </div>

    <!-- 提示框 -->
    <div class="toast-container">
        <div class="toast align-items-center text-white bg-success" id="successToast" role="alert" aria-live="assertive" aria-atomic="true">
            <div class="d-flex">
                <div class="toast-body">操作成功</div>
                <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
            </div>
        </div>
        <div class="toast align-items-center text-white bg-danger" id="errorToast" role="alert" aria-live="assertive" aria-atomic="true">
            <div class="d-flex">
                <div class="toast-body" id="errorMsg">操作失败</div>
                <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
            </div>
        </div>
    </div>

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/js/bootstrap.bundle.min.js"></script>
    <script>
        // 检查必要的库是否加载
        function checkLibraries() {
            if (typeof $ === 'undefined') {
                throw new Error('jQuery未正确加载');
            }
            if (typeof bootstrap === 'undefined') {
                throw new Error('Bootstrap未正确加载');
            }
        }

        class DataTableManager {
            constructor() {
                try {
                    checkLibraries();
                    
                    this.data = [];
                    this.filteredData = [];
                    this.currentSort = { column: null, direction: 'asc' };
                    this.editingId = null;
                    this.currentPage = 1;
                    this.pageSize = 10;
                    this.modal = new bootstrap.Modal(document.getElementById('editModal'));
                    this.successToast = new bootstrap.Toast(document.getElementById('successToast'));
                    this.errorToast = new bootstrap.Toast(document.getElementById('errorToast'));
                    
                    this.initElements();
                    this.bindEvents();
                    this.loadData();
                } catch (error) {
                    this.showLibraryError(error);
                }
            }
            
            showLibraryError(error) {
                document.getElementById('tableBody').innerHTML = `
                    <tr>
                        <td colspan="100" class="empty-table">
                            <i class="fas fa-exclamation-triangle"></i> 初始化失败: ${error.message}<br>
                            请刷新页面或检查网络连接
                        </td>
                    </tr>
                `;
                console.error('初始化错误:', error);
            }
            
            initElements() {
                this.elements = {
                    tableHeader: document.getElementById('tableHeader'),
                    tableBody: document.getElementById('tableBody'),
                    searchInput: document.getElementById('searchInput'),
                    addBtn: document.getElementById('addBtn'),
                    exportBtn: document.getElementById('exportBtn'),
                    modalTitle: document.getElementById('modalTitle'),
                    modalForm: document.getElementById('modalForm'),
                    saveBtn: document.getElementById('saveBtn'),
                    pagination: document.getElementById('pagination'),
                    pageSizeSelect: document.getElementById('pageSizeSelect')
                };
            }
            
            bindEvents() {
                this.elements.searchInput.addEventListener('input', () => {
                    this.currentPage = 1;
                    this.filterData();
                });
                this.elements.addBtn.addEventListener('click', () => this.showAddModal());
                this.elements.saveBtn.addEventListener('click', () => this.saveRecord());
                this.elements.exportBtn.addEventListener('click', () => this.exportData());
                this.elements.pageSizeSelect.addEventListener('change', () => {
                    this.pageSize = parseInt(this.elements.pageSizeSelect.value);
                    this.currentPage = 1;
                    this.renderTable();
                });
            }
            
            async loadData() {
                try {
                    // 使用模拟数据，实际应用中替换为wusiFetch调用
                    // const response = await wusiFetch('https://api.example.com/data');
                    // this.data = await response.json();
                    
                    // 模拟数据
                    this.data = [
                        { id: 1, name: '张三', age: 28, email: 'zhangsan@example.com', department: '研发部' },
                        { id: 2, name: '李四', age: 32, email: 'lisi@example.com', department: '市场部' },
                        { id: 3, name: '王五', age: 25, email: 'wangwu@example.com', department: '人事部' },
                        { id: 4, name: '赵六', age: 40, email: 'zhaoliu@example.com', department: '财务部' },
                        { id: 5, name: '钱七', age: 35, email: 'qianqi@example.com', department: '研发部' },
                        { id: 6, name: '孙八', age: 29, email: 'sunba@example.com', department: '市场部' },
                        { id: 7, name: '周九', age: 31, email: 'zhoujiu@example.com', department: '人事部' },
                        { id: 8, name: '吴十', age: 27, email: 'wushi@example.com', department: '研发部' },
                        { id: 9, name: '郑十一', age: 38, email: 'zhengshiyi@example.com', department: '财务部' },
                        { id: 10, name: '王十二', age: 33, email: 'wangshier@example.com', department: '市场部' },
                        { id: 11, name: '李十三', age: 26, email: 'lishisan@example.com', department: '研发部' },
                        { id: 12, name: '张十四', age: 42, email: 'zhangshisi@example.com', department: '人事部' }
                    ];
                    
                    this.filteredData = [...this.data];
                    this.renderTable();
                } catch (error) {
                    this.showError('加载数据失败: ' + error.message);
                    this.elements.tableBody.innerHTML = `
                        <tr>
                            <td colspan="100" class="empty-table">
                                <i class="fas fa-exclamation-triangle"></i> 数据加载失败，请刷新重试
                            </td>
                        </tr>
                    `;
                }
            }
            
            getPaginatedData() {
                const start = (this.currentPage - 1) * this.pageSize;
                const end = start + this.pageSize;
                return this.filteredData.slice(start, end);
            }
            
            renderTable() {
                if (this.filteredData.length === 0) {
                    this.elements.tableBody.innerHTML = `
                        <tr>
                            <td colspan="100" class="empty-table">
                                没有找到匹配的数据
                            </td>
                        </tr>
                    `;
                    this.renderPagination();
                    return;
                }
                
                // 渲染表头
                const headers = Object.keys(this.filteredData[0]);
                let headerHtml = '';
                headers.forEach(header => {
                    headerHtml += `
                        <th>
                            ${header}
                            <span class="sort-icon" data-column="${header}">
                                <i class="fas fa-sort"></i>
                            </span>
                        </th>
                    `;
                });
                headerHtml += '<th>操作</th>';
                this.elements.tableHeader.innerHTML = headerHtml;
                
                // 绑定排序事件
                document.querySelectorAll('.sort-icon').forEach(icon => {
                    icon.addEventListener('click', (e) => {
                        const column = e.currentTarget.getAttribute('data-column');
                        this.sortData(column);
                    });
                });
                
                // 渲染表格内容
                const paginatedData = this.getPaginatedData();
                let bodyHtml = '';
                paginatedData.forEach(item => {
                    let rowHtml = '';
                    headers.forEach(header => {
                        rowHtml += `<td>${item[header]}</td>`;
                    });
                    
                    rowHtml += `
                        <td>
                            <button class="btn btn-sm btn-outline-primary action-btn edit-btn" data-id="${item.id}">
                                <i class="fas fa-edit"></i>
                            </button>
                            <button class="btn btn-sm btn-outline-danger action-btn delete-btn" data-id="${item.id}">
                                <i class="fas fa-trash"></i>
                            </button>
                        </td>
                    `;
                    
                    bodyHtml += `<tr>${rowHtml}</tr>`;
                });
                
                this.elements.tableBody.innerHTML = bodyHtml;
                this.renderPagination();
                
                // 绑定编辑和删除事件
                document.querySelectorAll('.edit-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        const id = parseInt(e.currentTarget.getAttribute('data-id'));
                        this.showEditModal(id);
                    });
                });
                
                document.querySelectorAll('.delete-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        const id = parseInt(e.currentTarget.getAttribute('data-id'));
                        this.confirmDelete(id);
                    });
                });
            }
            
            renderPagination() {
                const totalPages = Math.ceil(this.filteredData.length / this.pageSize);
                let paginationHtml = '';
                
                // 上一页按钮
                paginationHtml += `
                    <li class="page-item ${this.currentPage === 1 ? 'disabled' : ''}">
                        <a class="page-link" href="#" data-page="${this.currentPage - 1}">&laquo;</a>
                    </li>
                `;
                
                // 页码按钮
                const maxVisiblePages = 5;
                let startPage = Math.max(1, this.currentPage - Math.floor(maxVisiblePages / 2));
                let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
                
                if (endPage - startPage + 1 < maxVisiblePages) {
                    startPage = Math.max(1, endPage - maxVisiblePages + 1);
                }
                
                for (let i = startPage; i <= endPage; i++) {
                    paginationHtml += `
                        <li class="page-item ${i === this.currentPage ? 'active' : ''}">
                            <a class="page-link" href="#" data-page="${i}">${i}</a>
                        </li>
                    `;
                }
                
                // 下一页按钮
                paginationHtml += `
                    <li class="page-item ${this.currentPage === totalPages ? 'disabled' : ''}">
                        <a class="page-link" href="#" data-page="${this.currentPage + 1}">&raquo;</a>
                    </li>
                `;
                
                this.elements.pagination.innerHTML = paginationHtml;
                
                // 绑定分页事件
                document.querySelectorAll('.page-link').forEach(link => {
                    link.addEventListener('click', (e) => {
                        e.preventDefault();
                        const page = parseInt(e.currentTarget.getAttribute('data-page'));
                        if (page >= 1 && page <= totalPages && page !== this.currentPage) {
                            this.currentPage = page;
                            this.renderTable();
                        }
                    });
                });
            }
            
            filterData() {
                const searchTerm = this.elements.searchInput.value.toLowerCase();
                this.filteredData = this.data.filter(item => {
                    return Object.values(item).some(value => 
                        String(value).toLowerCase().includes(searchTerm)
                    );
                });
                this.renderTable();
            }
            
            sortData(column) {
                if (this.currentSort.column === column) {
                    this.currentSort.direction = this.currentSort.direction === 'asc' ? 'desc' : 'asc';
                } else {
                    this.currentSort.column = column;
                    this.currentSort.direction = 'asc';
                }
                
                this.filteredData.sort((a, b) => {
                    const valA = a[column];
                    const valB = b[column];
                    
                    if (valA < valB) return this.currentSort.direction === 'asc' ? -1 : 1;
                    if (valA > valB) return this.currentSort.direction === 'asc' ? 1 : -1;
                    return 0;
                });
                
                this.currentPage = 1;
                this.renderTable();
            }
            
            showAddModal() {
                this.editingId = null;
                this.elements.modalTitle.textContent = '添加记录';
                
                const headers = this.data.length > 0 ? Object.keys(this.data[0]) : [];
                let formHtml = '';
                headers.forEach(header => {
                    if (header !== 'id') {
                        formHtml += `
                            <div class="mb-3">
                                <label for="${header}" class="form-label">${header}</label>
                                <input type="${header === 'age' ? 'number' : 'text'}" class="form-control" id="${header}">
                                <div class="invalid-feedback" id="${header}Error"></div>
                            </div>
                        `;
                    }
                });
                
                this.elements.modalForm.innerHTML = formHtml;
                this.modal.show();
            }
            
            showEditModal(id) {
                this.editingId = id;
                this.elements.modalTitle.textContent = '编辑记录';
                
                const record = this.data.find(item => item.id === id);
                if (!record) return;
                
                const headers = Object.keys(record);
                let formHtml = '';
                headers.forEach(header => {
                    if (header !== 'id') {
                        formHtml += `
                            <div class="mb-3">
                                <label for="${header}" class="form-label">${header}</label>
                                <input type="${header === 'age' ? 'number' : 'text'}" class="form-control" id="${header}" value="${record[header]}">
                                <div class="invalid-feedback" id="${header}Error"></div>
                            </div>
                        `;
                    }
                });
                
                this.elements.modalForm.innerHTML = formHtml;
                this.modal.show();
            }
            
            validateForm() {
                let isValid = true;
                const headers = this.data.length > 0 ? Object.keys(this.data[0]) : [];
                
                headers.forEach(header => {
                    if (header !== 'id') {
                        const input = document.getElementById(header);
                        const errorElement = document.getElementById(`${header}Error`);
                        
                        if (input) {
                            input.classList.remove('is-invalid');
                            errorElement.textContent = '';
                            
                            // 必填验证
                            if (!input.value.trim()) {
                                input.classList.add('is-invalid');
                                errorElement.textContent = '此项为必填项';
                                isValid = false;
                                return;
                            }
                            
                            // 特殊字段验证
                            if (header === 'email') {
                                const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
                                if (!emailRegex.test(input.value)) {
                                    input.classList.add('is-invalid');
                                    errorElement.textContent = '请输入有效的邮箱地址';
                                    isValid = false;
                                    return;
                                }
                            }
                            
                            if (header === 'age') {
                                const age = parseInt(input.value);
                                if (isNaN(age) || age < 18 || age > 100) {
                                    input.classList.add('is-invalid');
                                    errorElement.textContent = '年龄必须在18-100之间';
                                    isValid = false;
                                    return;
                                }
                            }
                        }
                    }
                });
                
                return isValid;
            }
            
            saveRecord() {
                if (!this.validateForm()) {
                    return;
                }
                
                const headers = this.data.length > 0 ? Object.keys(this.data[0]) : [];
                const newRecord = {};
                
                headers.forEach(header => {
                    if (header !== 'id') {
                        const input = document.getElementById(header);
                        if (input) {
                            newRecord[header] = header === 'age' ? parseInt(input.value) : input.value;
                        }
                    }
                });
                
                if (this.editingId === null) {
                    // 添加新记录
                    newRecord.id = this.data.length > 0 ? Math.max(...this.data.map(item => item.id)) + 1 : 1;
                    this.data.push(newRecord);
                    this.showSuccess('记录添加成功');
                } else {
                    // 更新记录
                    const index = this.data.findIndex(item => item.id === this.editingId);
                    if (index !== -1) {
                        this.data[index] = { ...this.data[index], ...newRecord };
                        this.showSuccess('记录更新成功');
                    }
                }
                
                this.filterData();
                this.modal.hide();
            }
            
            confirmDelete(id) {
                if (confirm('确定要删除这条记录吗？')) {
                    this.data = this.data.filter(item => item.id !== id);
                    this.filterData();
                    this.showSuccess('记录删除成功');
                }
            }
            
            exportData() {
                if (this.filteredData.length === 0) {
                    this.showError('没有数据可导出');
                    return;
                }
                
                try {
                    const headers = Object.keys(this.filteredData[0]);
                    let csvContent = headers.join(',') + '\n';
                    
                    this.filteredData.forEach(item => {
                        const row = headers.map(header => {
                            let value = item[header];
                            // 处理包含逗号的值
                            if (typeof value === 'string' && value.includes(',')) {
                                return `"${value}"`;
                            }
                            return value;
                        });
                        csvContent += row.join(',') + '\n';
                    });
                    
                    // 创建Blob对象
                    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
                    const url = URL.createObjectURL(blob);
                    
                    // 使用系统分享功能
                    if (navigator.share) {
                        navigator.share({
                            title: '表格数据导出',
                            text: '导出的表格数据',
                            url: url
                        }).catch(err => {
                            console.error('分享失败:', err);
                            this.downloadFile(blob);
                        });
                    } else {
                        this.downloadFile(blob);
                    }
                    
                    this.showSuccess('数据导出成功');
                } catch (error) {
                    this.showError('导出失败: ' + error.message);
                }
            }
            
            downloadFile(blob) {
                const link = document.createElement('a');
                link.href = URL.createObjectURL(blob);
                link.download = `data_export_${new Date().toISOString().slice(0, 10)}.csv`;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            }
            
            showSuccess(message) {
                document.querySelector('#successToast .toast-body').textContent = message;
                this.successToast.show();
            }
            
            showError(message) {
                document.getElementById('errorMsg').textContent = message;
                this.errorToast.show();
            }
        }
        
        // 初始化应用
        document.addEventListener('DOMContentLoaded', () => {
            try {
                new DataTableManager();
            } catch (error) {
                console.error('应用初始化失败:', error);
                document.getElementById('tableBody').innerHTML = `
                    <tr>
                        <td colspan="100" class="empty-table">
                            <i class="fas fa-exclamation-triangle"></i> 应用初始化失败: ${error.message}
                        </td>
                    </tr>
                `;
            }
        });
    </script>
</body>
</html>
